<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SpringBoot启动流程解析 | 技术小馆</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        .hero {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        }
        .article-content h2 {
            font-family: 'Noto Serif SC', serif;
            color: #2d3748;
            font-weight: 600;
            margin-top: 2.5rem;
            margin-bottom: 1.5rem;
            border-bottom: 2px solid #edf2f7;
            padding-bottom: 0.5rem;
        }
        .article-content h3 {
            font-family: 'Noto Serif SC', serif;
            color: #4a5568;
            font-weight: 500;
            margin-top: 1.8rem;
            margin-bottom: 1rem;
        }
        .article-content p {
            margin-bottom: 1.2rem;
        }
        .article-content ul {
            list-style-type: disc;
            padding-left: 1.5rem;
            margin-bottom: 1.5rem;
        }
        .article-content li {
            margin-bottom: 0.5rem;
        }
        .code-block {
            background-color: #f8fafc;
            border-radius: 0.5rem;
            padding: 1.5rem;
            margin: 1.5rem 0;
            font-family: monospace;
            border-left: 4px solid #667eea;
            overflow-x: auto;
        }
        .highlight {
            background-color: #fff9c2;
            padding: 0.2rem 0.4rem;
            border-radius: 0.2rem;
        }
        .card {
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .icon-rotate {
            transition: transform 0.3s ease;
        }
        .card:hover .icon-rotate {
            transform: rotate(15deg);
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="hero text-white py-20">
        <div class="container mx-auto px-6">
            <div class="max-w-4xl mx-auto text-center">
                <h1 class="text-4xl md:text-5xl font-bold mb-6 font-serif">SpringBoot启动流程深度解析</h1>
                <p class="text-xl md:text-2xl mb-8 opacity-90">探索SpringBoot如何简化应用启动过程，揭秘背后的自动配置魔法</p>
                <div class="flex justify-center space-x-4">
                    <div class="bg-white bg-opacity-20 px-6 py-3 rounded-full inline-flex items-center">
                        <i class="fas fa-code-branch mr-2"></i>
                        <span>核心源码分析</span>
                    </div>
                    <div class="bg-white bg-opacity-20 px-6 py-3 rounded-full inline-flex items-center">
                        <i class="fas fa-project-diagram mr-2"></i>
                        <span>启动流程详解</span>
                    </div>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto px-6 py-12 max-w-5xl">
        <article class="article-content">
            <!-- Introduction -->
            <div class="bg-white rounded-xl shadow-md p-8 mb-12 card">
                <div class="flex items-center mb-6">
                    <div class="bg-blue-100 p-3 rounded-full mr-4">
                        <i class="fas fa-rocket text-blue-600 text-xl icon-rotate"></i>
                    </div>
                    <h2 class="text-3xl font-bold">SpringBoot启动流程</h2>
                </div>
                <p><code class="highlight">SpringApplication</code> 是 Spring Boot 的核心类之一，用于启动 Spring 应用程序。它封装了应用的启动过程，包括创建应用上下文、启动自动配置、扫描组件、以及运行嵌入式 Web 服务器等一系列操作。Spring Boot 的启动流程是其简化开发体验的重要组成部分。</p>
            </div>

            <!-- Section 1 -->
            <div class="bg-white rounded-xl shadow-md p-8 mb-12 card">
                <div class="flex items-center mb-6">
                    <div class="bg-purple-100 p-3 rounded-full mr-4">
                        <i class="fas fa-cube text-purple-600 text-xl icon-rotate"></i>
                    </div>
                    <h2 class="text-3xl font-bold">1. SpringApplication 类概述</h2>
                </div>
                <p><code class="highlight">SpringApplication</code> 类的核心职责是启动 Spring 应用并配置应用上下文。它的主要功能是：</p>
                <ul>
                    <li>加载 Spring 配置文件</li>
                    <li>创建 Spring 上下文（如 <code class="highlight">AnnotationConfigApplicationContext</code> 或 <code class="highlight">GenericWebApplicationContext</code>）</li>
                    <li>启动自动配置机制</li>
                    <li>执行容器启动</li>
                    <li>配置嵌入式 Web 服务器（如果是 Web 应用）</li>
                </ul>
                <p>在 Spring Boot 中，<code class="highlight">SpringApplication</code> 主要通过 <code class="highlight">run()</code> 方法来启动整个应用。</p>
            </div>

            <!-- Section 2 -->
            <div class="bg-white rounded-xl shadow-md p-8 mb-12 card">
                <div class="flex items-center mb-6">
                    <div class="bg-green-100 p-3 rounded-full mr-4">
                        <i class="fas fa-code text-green-600 text-xl icon-rotate"></i>
                    </div>
                    <h2 class="text-3xl font-bold">2. SpringApplication 的关键构造方法</h2>
                </div>
                <p>SpringApplication 类的构造方法主要有以下几种重载形式。通常，启动 Spring Boot 应用时会用到 <code class="highlight">run(String... args)</code> 方法。</p>
                <div class="code-block">
                    <pre>public class SpringApplication {
    private static final Log logger = LogFactory.getLog(SpringApplication.class);

    private final Class<?> primarySource;
    private final Set<Class<?>> sources = new LinkedHashSet<>();
    private ApplicationContext context;

    public SpringApplication(Class<?> primarySource) {
        Assert.notNull(primarySource, "Primary source must not be null");
        this.primarySource = primarySource;
        this.sources.add(primarySource);
    }

    public SpringApplication(Class<?>... primarySources) {
        Assert.notNull(primarySources, "Primary sources must not be null");
        this.primarySource = null;
        this.sources.addAll(Arrays.asList(primarySources));
    }
}</pre>
                </div>
                <h3>构造器作用</h3>
                <p>构造方法接收一个或多个类作为参数（如 <code class="highlight">@SpringBootApplication</code> 注解的主类）。这些类作为应用的主要源，将会用于构建应用上下文。</p>
                <ul>
                    <li><code class="highlight">primarySource</code>：<code class="highlight">primarySource</code> 是传入的主类，它通常是包含 <code class="highlight">@SpringBootApplication</code> 注解的类。</li>
                    <li><code class="highlight">sources</code>：<code class="highlight">sources</code> 是一个集合，存储了所有要加载的配置类（包括主类和任何其他的配置类）。</li>
                </ul>
            </div>

            <!-- Section 3 -->
            <div class="bg-white rounded-xl shadow-md p-8 mb-12 card">
                <div class="flex items-center mb-6">
                    <div class="bg-yellow-100 p-3 rounded-full mr-4">
                        <i class="fas fa-play-circle text-yellow-600 text-xl icon-rotate"></i>
                    </div>
                    <h2 class="text-3xl font-bold">3. run() 方法源码分析</h2>
                </div>
                <p><code class="highlight">run()</code> 方法是 <code class="highlight">SpringApplication</code> 启动应用的入口。它负责启动 Spring 容器并处理传入的参数。以下是 <code class="highlight">run()</code> 方法的部分源码：</p>
                <div class="code-block">
                    <pre>public ConfigurableApplicationContext run(String... args) {
    // 1. 解析命令行参数并初始化默认的环境
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();

    // 2. 设置环境变量，加载配置
    ApplicationEnvironment environment = prepareEnvironment(listeners, args);

    // 3. 创建应用上下文
    ConfigurableApplicationContext context = createApplicationContext();

    // 4. 准备上下文
    prepareContext(context, environment, listeners, args);

    // 5. 启动上下文
    refreshContext(context);

    // 6. 执行所有监听器（可用于扩展或执行启动逻辑）
    afterRefresh(context, args);

    // 7. 完成，返回应用上下文
    return context;
}</pre>
                </div>

                <div class="mt-8">
                    <h3>解析命令行参数并初始化环境</h3>
                    <div class="code-block">
                        <pre>SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();</pre>
                    </div>
                    <ul>
                        <li><code class="highlight">getRunListeners(args)</code>：该方法返回一组监听器，这些监听器会在应用启动过程中参与执行。Spring Boot 会创建 <code class="highlight">SpringApplicationRunListener</code> 实例，用于在启动过程中提供各种钩子方法。</li>
                        <li><code class="highlight">listeners.starting()</code>：通知监听器应用开始启动。</li>
                    </ul>

                    <h3>设置环境变量，加载配置</h3>
                    <div class="code-block">
                        <pre>ApplicationEnvironment environment = prepareEnvironment(listeners, args);</pre>
                    </div>
                    <p><code class="highlight">prepareEnvironment()</code> 方法用于创建和初始化 Spring 环境（<code class="highlight">Environment</code>）。它会设置应用的配置源，包括环境变量、系统属性、配置文件（如 <code class="highlight">application.properties</code>）等。</p>

                    <h3>创建应用上下文</h3>
                    <div class="code-block">
                        <pre>ConfigurableApplicationContext context = createApplicationContext();</pre>
                    </div>
                    <p><code class="highlight">createApplicationContext()</code>：该方法根据应用的类型（如 <code class="highlight">AnnotationConfigApplicationContext</code> 或 <code class="highlight">GenericWebApplicationContext</code>）来创建一个 Spring 上下文。对于 Web 应用，它会创建 <code class="highlight">GenericWebApplicationContext</code>，对于普通的应用，创建 <code class="highlight">AnnotationConfigApplicationContext</code>。</p>
                    <div class="code-block">
                        <pre>private ConfigurableApplicationContext createApplicationContext() {
    // 对于非 Web 应用，创建 AnnotationConfigApplicationContext
    if (this.webApplicationType == WebApplicationType.NONE) {
        return new AnnotationConfigApplicationContext();
    }
    // 对于 Web 应用，创建 Web 应用上下文
    return new GenericWebApplicationContext();
}</pre>
                    </div>

                    <h3>准备上下文</h3>
                    <div class="code-block">
                        <pre>prepareContext(context, environment, listeners, args);</pre>
                    </div>
                    <p><code class="highlight">prepareContext()</code> 会为上下文设置必要的环境（包括配置、属性、事件等），并将监听器注册到上下文中。</p>

                    <h3>刷新上下文</h3>
                    <div class="code-block">
                        <pre>refreshContext(context);</pre>
                    </div>
                    <p><code class="highlight">refreshContext()</code> 会启动 Spring 容器并加载所有的 Bean 定义。此时，Spring Boot 的自动配置、依赖注入、生命周期管理等会启动。</p>

                    <h3>执行后续操作</h3>
                    <div class="code-block">
                        <pre>afterRefresh(context, args);</pre>
                    </div>
                    <p><code class="highlight">afterRefresh()</code> 方法用于执行所有监听器注册的操作（如日志记录、事件通知等）。</p>
                </div>
            </div>

            <!-- Section 4 -->
            <div class="bg-white rounded-xl shadow-md p-8 mb-12 card">
                <div class="flex items-center mb-6">
                    <div class="bg-red-100 p-3 rounded-full mr-4">
                        <i class="fas fa-sitemap text-red-600 text-xl icon-rotate"></i>
                    </div>
                    <h2 class="text-3xl font-bold">4. SpringApplication 启动流程的详细解析</h2>
                </div>
                <ul>
                    <li><strong>启动监听器</strong>：Spring Boot 在启动时，会先获取并启动一系列的监听器。这些监听器可以用来扩展 Spring Boot 应用的行为，如日志输出、生命周期管理等。</li>
                    <li><strong>创建应用上下文</strong>：通过 <code class="highlight">createApplicationContext()</code> 方法，Spring Boot 创建了不同类型的上下文。Web 应用程序会创建 <code class="highlight">GenericWebApplicationContext</code>，非 Web 应用则会创建 <code class="highlight">AnnotationConfigApplicationContext</code>。</li>
                    <li><strong>配置源的加载</strong>：<code class="highlight">prepareEnvironment()</code> 方法加载了 Spring 环境（<code class="highlight">Environment</code>）以及应用的配置文件，如 <code class="highlight">application.properties</code> 或 <code class="highlight">application.yml</code>，并将它们注入到应用上下文中。</li>
                    <li><strong>自动配置</strong>：Spring Boot 自动配置机制通过扫描应用类路径，基于条件注解（如 <code class="highlight">@ConditionalOnClass</code>）自动加载所需的配置类。这些配置类通过 <code class="highlight">@Import(AutoConfigurationImportSelector.class)</code> 加载，并最终决定哪些自动配置类应该生效。</li>
                    <li><strong>刷新应用上下文</strong>：<code class="highlight">refreshContext()</code> 方法调用了 <code class="highlight">ConfigurableApplicationContext</code> 的 <code class="highlight">refresh()</code> 方法，执行容器的初始化和 Bean 的创建，完成整个应用的启动过程。</li>
                </ul>
            </div>

            <!-- Section 5 -->
            <div class="bg-white rounded-xl shadow-md p-8 mb-12 card">
                <div class="flex items-center mb-6">
                    <div class="bg-indigo-100 p-3 rounded-full mr-4">
                        <i class="fas fa-link text-indigo-600 text-xl icon-rotate"></i>
                    </div>
                    <h2 class="text-3xl font-bold">5. SpringApplication 与 SpringApplicationContext 的关系</h2>
                </div>
                <p><code class="highlight">SpringApplication</code> 是一个应用启动类，它处理所有的启动逻辑，包括创建上下文、加载配置、启动自动配置等。而 <code class="highlight">ApplicationContext</code> 则是 Spring 容器的具体实现，负责管理 Spring Bean 的生命周期和依赖注入。<code class="highlight">SpringApplication</code> 的主要作用就是启动应用上下文并交给 Spring 容器进行管理。</p>
            </div>

            <!-- Visualization -->
            <div class="bg-white rounded-xl shadow-md p-8 mb-12">
                <h2 class="text-3xl font-bold mb-6">SpringBoot启动流程可视化</h2>
                <div class="mermaid">
                    graph TD
                    A[SpringApplication.run()] --> B[初始化环境]
                    B --> C[创建应用上下文]
                    C --> D[准备上下文]
                    D --> E[刷新上下文]
                    E --> F[执行监听器]
                    F --> G[返回应用上下文]
                    
                    B --> B1[解析命令行参数]
                    B --> B2[加载配置文件]
                    
                    C --> C1[判断应用类型]
                    C1 -->|Web应用| C2[GenericWebApplicationContext]
                    C1 -->|非Web应用| C3[AnnotationConfigApplicationContext]
                    
                    D --> D1[设置环境变量]
                    D --> D2[注册Bean定义]
                    
                    E --> E1[BeanFactory初始化]
                    E --> E2[执行自动配置]
                    E --> E3[启动Web服务器]
                </div>
            </div>
        </article>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-100 py-12">
        <div class="container mx-auto px-6">
            <div class="max-w-5xl mx-auto">
                <div class="text-center">
                    <h3 class="text-xl font-bold mb-4">技术小馆</h3>
                    <a href="http://www.yuque.com/jtostring" class="text-blue-300 hover:text-blue-100 transition-colors duration-200">http://www.yuque.com/jtostring</a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>